﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Xml;
using DiscoveryLogic.Common.Utilities;

namespace DiscoveryLogic.DataViz.NetworkDiagram.NetworkData
{
    /// <summary>
    /// 
    /// </summary>
    public class LinkDataObject
    {
        private string _FromNetworkName;
        /// <summary></summary>
        public string FromNetworkName
        {
            get
            {
                return this._FromNetworkName;
            }
            set
            {
                this._FromNetworkName = value;
            }
        }

        private string _ToNetworkName;
        /// <summary></summary>
        public string ToNetworkName
        {
            get
            {
                return this._ToNetworkName;
            }
            set
            {
                this._ToNetworkName = value;
            }
        }

        private string _FromMemberName;
        /// <summary></summary>
        public string FromMemberName
        {
            get
            {
                return this._FromMemberName;
            }
            set
            {
                this._FromMemberName = value;
            }
        }

        private string _ToMemberName;
        /// <summary></summary>
        public string ToMemberName
        {
            get
            {
                return this._ToMemberName;
            }
            set
            {
                this._ToMemberName = value;
            }
        }

        private string _FromKey;
        /// <summary></summary>
        public string FromKey
        {
            get
            {
                return this._FromKey;
            }
            set
            {
                this._FromKey = value;
            }
        }

        private string _ToKey;
        /// <summary></summary>
        public string ToKey
        {
            get
            {
                return this._ToKey;
            }
            set
            {
                this._ToKey = value;
            }
        }
        
        private double _Distance;
        /// <summary></summary>
        public double Distance
        {
            get
            {
                return this._Distance;
            }
            set
            {
                this._Distance = value;
            }
        }

        private LinkType _RelationType;
        /// <summary></summary>
        public LinkType RelationType
        {
            get
            {
                return this._RelationType;
            }
            set
            {
                this._RelationType = value;
            }
        }


        private bool _IsAggregate;
        /// <summary></summary>
        public bool IsAggregate
        {
            get
            {
                return this._IsAggregate;
            }
            set
            {
                this._IsAggregate = value;
            }
        }

        private double _Possibility;
        /// <summary></summary>
        public double Possibility
        {
            get
            {
                return this._Possibility;
            }
            set
            {
                this._Possibility = value;
            }
        }

        private double _Weight;
        /// <summary></summary>
        public double Weight
        {
            get
            {
                return this._Weight;
            }
            set
            {
                this._Weight = value;
            }
        }

        private string _Evidence;
        /// <summary></summary>
        public string Evidence
        {
            get
            {
                return this._Evidence;
            }
            set
            {
                this._Evidence = value;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public LinkDataObject()
        {
            this._FromNetworkName = string.Empty;
            this._ToNetworkName = string.Empty;
            this._FromMemberName = string.Empty;
            this._ToMemberName = string.Empty;
            this._FromKey = string.Empty;
            this._ToKey = string.Empty;
            this._Distance = Double.PositiveInfinity;
            this._RelationType = LinkType.Citation;
            this._IsAggregate = false;
            this._Possibility = 1;
            this._Weight = 1;
            this._Evidence = string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        public LinkDataObject(string fromNet, string toNet,
            string fromMember, string toMember, string fromKey, string toKey,
            double distance)
        {
            this._FromNetworkName = fromNet;
            this._ToNetworkName = toNet;
            this._FromMemberName = fromMember;
            this._ToMemberName = toMember;
            this._FromKey = fromKey;
            this._ToKey = toKey;
            this._Distance = distance;
            this._RelationType = LinkType.Citation;
            this._IsAggregate = false;
            this._Possibility = 1;
            this._Weight = 1;
            this._Evidence = string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Dictionary<string, PropertyInfo> GetBindableMembers()
        {
            Dictionary<string, PropertyInfo> props = new Dictionary<string, PropertyInfo>();
            PropertyInfo[] propArray = this.GetType().GetProperties();
            if (propArray != null && propArray.Length > 0)
            {
                foreach (PropertyInfo prop in propArray)
                {
                    if (prop.CanWrite && prop.CanRead)
                    {
                        props.Add(prop.Name, prop);
                    }
                }
            }
            return props;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="distance"></param>
        /// <returns></returns>
        public bool Filter(double distance)
        {
            if(this.Distance <distance)
                return true;
            else
                return false;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xDoc"></param>
        /// <param name="eNode"></param>
        public void Save(ref XmlDocument xDoc, XmlNode eNode)
        {
            XmlNode tagNode = XmlDataUtil.AddElement(ref xDoc, eNode, "Tag");
            XmlDataUtil.UpdateAttribute(ref xDoc, tagNode, "Type", this.GetType().FullName);
            Dictionary<string, PropertyInfo> bindableProps = this.GetBindableMembers();
            foreach (string propName in bindableProps.Keys)
            {
                object propValue = bindableProps[propName].GetValue(this, null);
                if (propValue != null)
                {
                    SimpleDataType dataType = SimpleDataTypeUtil.ToSimpleDataType(bindableProps[propName].PropertyType);
                    string propValue2 = SimpleDataTypeUtil.ToDbValue(dataType, propValue).ToString();
                    XmlDataUtil.UpdateAttribute(ref xDoc, tagNode, propName, propValue2);
                }
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="eNode"></param>
        /// <returns></returns>
        public LinkDataObject Read(XmlNode eNode)
        {
            XmlNode tagNode = eNode.ChildNodes[0];
            if(tagNode==null)
                return null;
            string typeName = XmlDataUtil.GetAttributeValue(tagNode, "Type", "");
            if (this.GetType().FullName != typeName)
                throw new Exception("Type do not match");

            Dictionary<string, PropertyInfo> bindableProps = this.GetBindableMembers();
            LinkDataObject linkDO = (LinkDataObject)Activator.CreateInstance(this.GetType());
            foreach (string propName in bindableProps.Keys)
            {
                if (tagNode.Attributes.GetNamedItem(propName) != null)
                {
                    string propValue = XmlDataUtil.GetAttributeValue(tagNode, propName, "");
                    SimpleDataType simpleType = SimpleDataTypeUtil.ToSimpleDataType(bindableProps[propName].PropertyType);
                    object propValue2 = SimpleDataTypeUtil.ToDbValue(simpleType, propValue.ToString());
                    if (propValue2 != null && propValue2 !=DBNull.Value)
                        bindableProps[propName].SetValue(linkDO, propValue2, null);
                }
            }
            return linkDO;
        }
    }
}
